3

Maven是什么

Maven是跨平台的项目管理工具,主要服务于基于Java平台的项目构建、依赖管理和项目信息管理。

什么是构建

除了编写源代码,我们每天有相当一部分时间花在了编译、运行单元测试、生成文档、打包和部署等繁琐而不起眼的工作上,这就是构建build)。

Maven是优秀的构建工具

Maven可以自动化构建过程,从清理、编译、测试到生成报告,再到打包和部署。Maven最大化地消除了构建的重复,抽象了构建生命周期,并且为绝大部分的构建任务提供了已实现的插件,我们不再需要定义过程,甚至不需要再去实现这些过程中的一些任务。
最简单的例子就是测试,我们没必要告诉Maven去测试,更不需要告诉Maven如何运行测试,只需要遵循Maven的约定编写好测试用例当我们运行构建的时候,这些测试便会自动运行。

Maven不仅仅是构建工具

Maven不仅是构建工具,还是一个依赖管理工具盒项目信息管理工具。它提供了中央仓库,能帮助我们自动下载构件。

Maven依赖

根元素project下的dependencies可以包含一个或多个dependency元素,以声明一个或者多个项目依赖。每个依赖可以包含的元素有:

  • groupId, artifactId, version:依赖的基本坐标
  • type:依赖的类型,大部分情况下不必声明,默认为jar
  • scope:依赖的范围
  • optional:标记依赖是否可选
  • exclusions:用来排除传递性依赖

依赖范围

首先要弄清楚,Maven在不同的时候,使用了不同的classpath。Maven在编译项目主代码的时候使用compile classpath;在编译和执行测试的时候使用test classpath;在实际运行Maven项目的时候使用runtime classpath。
依赖范围就是用来控制依赖于这三种classpath(compile classpath, test classpath, runtime classpath)的关系。Maven有以下几种依赖范围:

  • compile:编译依赖范围,如果没有指定,默认使用该依赖范围
  • test:测试依赖范围,使用此依赖范围的Maven依赖,只对test classpath有效
  • provided:已提供依赖范围,使用此依赖范围的Maven依赖,对于compile和test classpath有效,但在运行时无效
  • runtime:运行时依赖范围,使用此依赖范围的Maven依赖,对于test和runtime classpath有效,但在编译主代码时无效
  • system:系统依赖范围,其与三种classpath的关系,和provided依赖范围一致

依赖范围与三种classpath的关系如下所示:

依赖范围Scope 对于compile classpath有效 对于test classpath有效 对于runtime classpath有效 例子
compile Y Y Y spring-core
test Y JUnit
provided Y Y servlet-api
runtime Y Y JDBC驱动实现
system Y Y 本地的Maven仓库职位的类库文件

传递性依赖

假设A依赖于B,B依赖于C,则A对于B是第一直接依赖,B对于C是第二直接依赖,A对于C是传递性依赖。第一直接依赖和第二直接依赖决定了传递性依赖的范围,如下表所示,最左边一列表示第一直接依赖范围,最上面一行表示第二直接依赖范围,中间的交叉单元格则表示传递性依赖范围。

compile test provided runtime
compile compile / / runtime
test test / / test
provided provided / provided provided
runtime runtime / / runtime

依赖仲裁

Maven依赖仲裁(Dependency Mediation):

  • 第一原则:最短路径优先原则
  • 第二原则:第一声明优先原则,在依赖路径长度相等的前提下,在POM中依赖声明最靠前的依赖优先

例如,项目A有这样的依赖关系:
1. A -> B -> C -> X(1.0),A -> D -> X(2.0),X(1.0)路径长度为3,X(2.0)路径长度为2,根据第一原则,X(2.0)会被解析使用;
2. A -> B -> Y(1.0),A -> C -> Y(2.0),Y(1.0)和Y(2.0)的依赖路径长度相同,如果B的依赖声明在C之前,那么Y(1.0)会被解析使用。

依赖相关的命令

  • mvn dependency:list 列出最终确定的依赖
  • mvn dependency:tree 打出依赖树
  • mvn dependency:analyze 依赖分析,给出项目中已使用但未声明的依赖,以及未使用但已声明的依赖

POM优化

依赖管理

  • 多模块项目中,定义一个主pom,在主pom中使用dependencyManagement定义依赖、版本和依赖排除
  • 子模块从主pom中继承依赖,一般情况下,不要在子模块中做依赖排除,也不要指定依赖版本

最佳实践

归类依赖

如果多个相关的依赖的版本都是相同的,可以使用properties元素定义Maven属性,依赖的版本值用这一属性引用表示。

<properties>
    <spring.version>2.5.6</spring.version>
</properties>

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring</artifactId>
        <version>${spring.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>${spring.version}</version>
    </dependency>
</dependencies>

参考资料

  1. Maven实战(Maven in Action)
  2. Maven权威指南

糖人
16 声望2 粉丝

« 上一篇
Book List for 2014